-------------------------------------------------------------------------------
-- Archivo: 			         index_unit.vhdl
-- Fecha de creación:            25/01/2011
-- Última fecha de modificación: 28/01/2011
-- Diseñador: 			         Cesar A. Fuguet T.
-- Diseño: 			             index_unit
-- Propósito: 			         Unidad generadora de direcciones de acceso al
--                               archivo de registros vectoriales
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use work.control_unit_pkg.all;
    
entity index_unit is
  
    port (
        OPCODE_i       : in  std_logic_vector(3 downto 0);
        COUNTER_i      : in  std_logic_vector(1 downto 0);
        VA_i           : in  std_logic_vector(1 downto 0);
        VB_i           : in  std_logic_vector(1 downto 0);
        VD_i           : in  std_logic_vector(1 downto 0);
        CONST2_i       : in  std_logic_vector(1 downto 0);
        HAZARD_FSM_i   : in  std_logic;
        HAZARD_NXT_i   : in  std_logic;
        FFT_STG_i      : in  std_logic_vector(2 downto 0);
        CLK_i          : in  std_logic;
        IDXI_o         : out std_logic_vector(3 downto 0);
        IDXJ_o         : out std_logic_vector(3 downto 0);
        IDXK_o         : out std_logic_vector(3 downto 0);
        CONST6_o       : out std_logic_vector(5 downto 0);
        CONST_MUX_o    : out std_logic;
        INSTR_FETCH_o  : out std_logic;
        WE_o           : out std_logic);
    end index_unit;

architecture behavioral of index_unit is
--    constant FFT_STAGE0 : std_logic_vector(2 downto 0) := "000";
--    constant FFT_STAGE1 : std_logic_vector(2 downto 0) := "001";
--    constant FFT_STAGE2 : std_logic_vector(2 downto 0) := "010";
--    constant FFT_STAGE3 : std_logic_vector(2 downto 0) := "011";
--    constant FFT_IDLE   : std_logic_vector(2 downto 0) := "111";

--    constant FFT_OPCODE : std_logic_vector(3 downto 0) := X"F";
--    constant LV_OPCODE  : std_logic_vector(3 downto 0) := X"D";
--    constant SV_OPCODE  : std_logic_vector(3 downto 0) := X"C";

    signal fft_indexes    : std_logic_vector(5 downto 0);
    signal curr_fft_index : std_logic_vector(3 downto 0);

    signal fft_idxi : std_logic_vector(3 downto 0);
    signal fft_idxj : std_logic_vector(3 downto 0);
    signal fft_idxk : std_logic_vector(3 downto 0);

    signal is_fft : std_logic;
    signal is_sv : std_logic;

    signal cnt1_xor_cnt0 : std_logic;
    
    signal const6_reg : std_logic_vector(5 downto 0);
    signal const6_wire : std_logic_vector(5 downto 0);
    
    signal const_mux_reg : std_logic;
    signal const_mux_wire : std_logic;

begin  -- behavioral

    is_fft <= '1' when (OPCODE_i = FFT_OPCODE) else
              '0';

    WE_o <= '0' 
        when ((HAZARD_FSM_i = '1' and is_fft = '0') 
             or (FFT_STG_i = FFT_IDLE) or (is_sv = '1')) else
            
            '1';

    INSTR_FETCH_o <= '1' when (HAZARD_NXT_i = '0') and (COUNTER_i = "11") else
                     '0';

    curr_fft_index <= FFT_STG_i(1 downto 0) & COUNTER_i;

    with curr_fft_index select
    fft_indexes <=
        "000010" when X"0",
        "000010" when X"2",
        "100010" when X"1",
        "100010" when X"3",
        "010111" when X"4",
        "010111" when X"6",
        "110111" when X"5",
        "110111" when X"7",
        "000001" when X"8",
        "000001" when X"A",
        "011011" when X"9",
        "011011" when X"B",
        "100001" when X"C",
        "100001" when X"E",
        "111011" when X"D",
        "111011" when others;


    cnt1_xor_cnt0 <= COUNTER_i(1) xor COUNTER_i(0);

    fft_idxk <= (VA_i & fft_indexes(5 downto 4)) when COUNTER_i(1) = '0' else
              (VB_i & fft_indexes(5 downto 4));

    fft_idxi <= (VA_i & fft_indexes(3 downto 2)) when COUNTER_i(1) = '0' else
              (VB_i & fft_indexes(3 downto 2));

    fft_idxj <= (VA_i & fft_indexes(1 downto 0)) 
                    when COUNTER_i(1) = '0' and FFT_STG_i(1) = '0' else
                (VB_i & fft_indexes(1 downto 0))
                    when COUNTER_i(1) = '1' and FFT_STG_i(1) = '0' else
                (VA_i & fft_indexes(1 downto 0)) 
                    when cnt1_xor_cnt0 = '0' and FFT_STG_i(1) = '1' else
                (VB_i & fft_indexes(1 downto 0));

    is_sv <= '1' when (OPCODE_i = SV_OPCODE) else
             '0';

    IDXI_o <= fft_idxi 
                when (is_fft = '1') else
              (VD_i & COUNTER_i)
                when (is_sv = '1') else
              (VA_i & COUNTER_i);

    IDXJ_o <= fft_idxj 
                when (is_fft = '1') else
              (VB_i & COUNTER_i);

    IDXK_o <= fft_idxk when (is_fft = '1') else
            (VD_i & COUNTER_i);

    const_mux_wire <= '1' when OPCODE_i(3 downto 2) = "10" else
                      '0'; 

    process(CLK_i)
    begin
        if(CLK_i = '1' and CLK_i'event) then
            const_mux_reg <= const_mux_wire;
        end if;
    end process;

    CONST_MUX_o <= const_mux_reg; 

    const6_wire <= VA_i & VB_i & CONST2_i;

    process(CLK_i, const6_wire)
    begin
        if (CLK_i = '1' and CLK_i'event) then
            const6_reg <= const6_wire;
        end if;
    end process; 

    CONST6_o <= const6_reg;

end behavioral;

-- vim: tabstop=4 : expandtab : shiftwidth=4
